#include "page_manager.h"


static uint8_t MaxPage;
static PageList_TypeDef* PageList;
uint8_t NowPage, LastPage, NextPage;
uint8_t NewPage, OldPage;
static uint8_t IsPageBusy; 

uint8_t PageStack[PAGE_STACK_SIZE];
uint8_t PageStackSize = PAGE_STACK_SIZE;
uint8_t PageStackTop;

uint8_t page_clear(uint8_t _PageID);

void page_manager_init(PageList_TypeDef *_PageList, uint8_t _MaxPage)
{
    PageList = _PageList; 
    MaxPage = _MaxPage;
    NewPage = 0;
    OldPage = 0;
    IsPageBusy = false;
    for(uint8_t page = 0; page < MaxPage; page++)
    {
        page_clear(page);
    }

}

/**
  * @brief  注册一个基本页面，包含一个初始化函数，循环函数，退出函数，事件函数
  * @param  pageID: 页面编号
  * @param  setupCallback: 初始化函数回调
  * @param  loopCallback: 循环函数回调
  * @param  exitCallback: 退出函数回调
  * @param  eventCallback: 事件函数回调
  * @retval true:成功 false:失败
  */
uint8_t page_register(
            uint8_t _PageID,
            CallbackFunction_t _SetupCallback,
            CallbackFunction_t _LoopCallback,
            CallbackFunction_t _ExitCallback,
            EventFunction_t _EventCallback)
{
    if(!IS_PAGE(_PageID))
        return false;

    PageList[_PageID].SetupCallback = _SetupCallback;
    PageList[_PageID].LoopCallback = _LoopCallback;
    PageList[_PageID].ExitCallback = _ExitCallback;
    PageList[_PageID].EventCallback = _EventCallback;
    
    return true;
}


/**
  * @brief  清除一个页面
  * @param  pageID: 页面编号
  * @retval true:成功 false:失败
  */
uint8_t page_clear(uint8_t _PageID)
{
    if(!IS_PAGE(_PageID))
        return false;

    PageList[_PageID].SetupCallback = NULL;
    PageList[_PageID].LoopCallback = NULL;
    PageList[_PageID].ExitCallback = NULL;
    PageList[_PageID].EventCallback = NULL;
    
    return true;
}

/**
  * @brief  清空页面栈
  * @param  无
  * @retval 无
  */
void page_stack_clear(void)
{
    /*检查页面是否忙碌*/
    if(IsPageBusy)
       return; 
    /*清除栈中左右数据*/
    for(uint8_t i = 0; i < PageStackSize; i++)
    {
        PageStack[i] = 0;
    }
    /*栈顶指针复位*/
    PageStackTop = 0;
}


/**
  * @brief  切换到指定页面
  * @param  pageID: 页面编号
  * @retval 无
  */
void page_change_to(uint8_t _PageID)
{
    if(!IS_PAGE(_PageID))
        return;
    
    /*检查页面是否忙碌*/
    if(!IsPageBusy)
    {
        /*新页面ID*/
        NextPage = NewPage = _PageID;

        /*标记为忙碌状态*/
        IsPageBusy = true;
    }
}


/**
  * @brief  页面事件传递
  * @param  obj: 发生事件的对象
  * @param  event: 事件编号
  * @retval 无
  */
void page_event_transmit(void *obj, int event)
{
    /*将事件传递到当前页面*/
    if(PageList[NowPage].EventCallback != NULL)
        PageList[NowPage].EventCallback(obj, event);
}


/**
  * @brief  页面压栈，跳转至该页面
  * @param  pageID: 页面编号
  * @retval true:成功 false:失败
  */
uint8_t page_push(uint8_t _PageID)
{
    if(!IS_PAGE(_PageID))
        return false;
    
    /*检查页面是否忙碌*/
    if(IsPageBusy)
       return false; 
    
    /*防止栈溢出*/
    if(PageStackTop >= PageStackSize - 1)
        return false;
    
    /*防止重复页面压栈*/
    if(_PageID == PageStack[PageStackTop])
        return false;

    /*栈顶指针上移*/
    PageStackTop++;
    
    /*页面压栈*/
    PageStack[PageStackTop] = _PageID;
    
    /*页面跳转*/
    page_change_to(PageStack[PageStackTop]);
    
    return true;
}

/**
  * @brief  页面弹栈，跳转至上一个页面
  * @param  无
  * @retval true:成功 false:失败
  */
uint8_t page_pop(void)
{
    /*检查页面是否忙碌*/
    if(IsPageBusy)
       return false; 
    
    /*防止栈溢出*/
    if(PageStackTop == 0)
        return false;
    
    /*清空当前页面*/
    PageStack[PageStackTop] = 0;
    
    /*弹栈，栈顶指针下移*/
    PageStackTop--;
    
    /*页面跳转*/
    page_change_to(PageStack[PageStackTop]);
    
    return true;
}

/**
  * @brief  页面调度器状态机
  * @param  无
  * @retval 无
  */
void page_run(void)
{
    /*页面切换事件*/
    if(NewPage != OldPage)
    {
        /*标记为忙碌状态*/
        IsPageBusy = true;

        /*触发旧页面退出事件*/
        if(PageList[OldPage].ExitCallback != NULL && IS_PAGE(OldPage))
            PageList[OldPage].ExitCallback();
        
        /*标记旧页面*/
        LastPage = OldPage;
        
        /*标记新页面为当前页面*/
        NowPage = NewPage;

        /*触发新页面初始化事件*/
        if(PageList[NewPage].SetupCallback != NULL && IS_PAGE(NewPage))
            PageList[NewPage].SetupCallback();

        /*新页面初始化完成，标记为旧页面*/
        OldPage = NewPage;
    }
    else
    {
        /*标记页面不忙碌，处于循环状态*/
        IsPageBusy = false;
        
        /*页面循环事件*/
        if(PageList[NowPage].LoopCallback != NULL && IS_PAGE(NowPage))
            PageList[NowPage].LoopCallback();
    }
}














